package com.sheepone.util.beanconvert.doublearray;

import com.sheepone.util.ClassUtil;
import com.sheepone.util.ArrayUtil;
import com.sheepone.util.number.NumberUtil;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.List;

/**
 * @author Miss.杨
 * @description
 * @since 2024/3/4 - 16:37
 */
public class DoubleArrayBeanConvertUtil {

    /**
     * 将对象数组转换为二维double数组
     *
     * @param objects
     * @param mapping
     * @return
     * @throws Exception
     */
    public static <T> double[][] objectsToDouble2DArray(T[] objects, DoubleArrayFieldCovertMapping<T> mapping) {
        int size = objects.length;
        double[][] array = new double[size][mapping.getTotalNum()];
        for (int i = 0; i < size; i++) {
            array[i] = objectToDoubleArray(objects[i], mapping);
        }
        return array;
    }

    /**
     * 将对象List转换为二维double二维数组
     *
     * @param objects
     * @param mapping
     * @return
     * @throws Exception
     */
    public static <T> double[][] objectsToDouble2DArray(List<T> objects, DoubleArrayFieldCovertMapping<T> mapping) {
        int size = objects.size();
        double[][] array = new double[size][mapping.getTotalNum()];
        for (int i = 0; i < size; i++) {
            array[i] = objectToDoubleArray(objects.get(i), mapping);
        }
        return array;
    }

    /**
     * 将对象转换为double数组
     *
     * @param object
     * @param mapping
     * @return
     * @throws Exception
     */
    public static <T> double[] objectToDoubleArray(T object, DoubleArrayFieldCovertMapping<T> mapping) {
        try {
            int totalNum = mapping.getTotalNum();
            double[] array = new double[totalNum];
            int[] nums = mapping.getIndexNums();
            Class[] fieldTypes = mapping.getFieldTypes();
            int index = 0;
            Field[] fields = mapping.getFields();
            for (int i = 0; i < fields.length; i++) {
                if (fieldTypes[i].isArray()) {
                    Object[] objs = (Object[]) fields[i].get(object);
                    for (int j = 0; j < nums[i]; j++) {
                        array[index++] = NumberUtil.numberToDouble(objs[j]);
                    }
                } else {
                    array[index++] = NumberUtil.numberToDouble(fields[i].get(object));
                }
            }
            return array;
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将二维double数组转换为对象数组
     *
     * @param array
     * @param mapping
     * @return
     * @throws Exception
     */
    public static <T> T[] double2DArrayToObjectArray(double[][] array, DoubleArrayFieldCovertMapping<T> mapping) {
        T[] objects = ArrayUtil.newArray(mapping.getClazz(), array.length);
        for (int i = 0; i < array.length; i++) {
            objects[i] = doubleArrayToObject(array[i], mapping);
        }
        return objects;
    }

    /**
     * 将double数组转换为对象
     *
     * @param array
     * @param mapping
     * @return
     * @throws Exception
     */
    public static <T> T doubleArrayToObject(double[] array, DoubleArrayFieldCovertMapping<T> mapping) {
        T object = null;
        try {
            Constructor<T> constructor = ClassUtil.getConstructor(mapping.getClazz());
            constructor.setAccessible(true);
            object = constructor.newInstance();
            int[] nums = mapping.getIndexNums();
            Field[] fields = mapping.getFields();
            Class[] fieldTypes = mapping.getFieldTypes();
            int index = 0;
            for (int i = 0; i < fields.length; i++) {
                if (fieldTypes[i].isArray()) {
                    Class componentType = fieldTypes[i].getComponentType();
                    Object[] values = (Object[]) NumberUtil.newNumberArrayByType(nums[i], componentType);
                    for (int j = 0; j < nums[i]; j++) {
                        double value = array[index++];
                        values[j] = NumberUtil.convertNumber(value, componentType);
                    }
                    fields[i].set(object, values);
                } else {
                    fields[i].set(object, array[index++]);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return object;
    }
}
